/*
 * HorsePart.cpp
 *
 *  Created on: Sep 18, 2017
 *      Author: gaoyi
 */

#include "HorsePart.h"
#include "Common/TableData/MountMountCfg.h"
#include "Character/PackagePart.h"
#include "Common/TableData/ItemItemCfg.h"
#include "Character/Player.h"
#include "Common/AttrMgr/AttrMgr.h"
#include "Common/TableData/FunctionunlockFunctionUnlockCfg.h"


#define HORSE_PART_TIMER 0
#define HORSE_PART_TIMER_INTERNAL 5000
HorsePart::HorsePart()
{

}

HorsePart::~HorsePart()
{

}

int	 HorsePart::CheckLevel()
{
	int maxLevel = 0;
	const FunctionunlockFunctionUnlockCfgInfo *pCfgInfo = g_GetFunctionunlockFunctionUnlockCfgTable()->GetFunctionunlockFunctionUnlockCfgInfo(FunctionUnlock_ID_TYPE_OPEN_HORSE_LEVEL);
	if (pCfgInfo)
	{
		maxLevel = pCfgInfo->unlockLevel;
	}
	int level = m_pMaster->GetAttr(C_LEVEL);
	if (level < maxLevel)
	{
		return	RET_HORSE_PLAYER_LEVEL;
	}
	return 0;
}

bool HorsePart::SaveToPB(::ProtoBuf::CharacterHorseInfo& horseInfo)
{
	horseInfo.set_cur_horse_id(mCurHorseId);
	horseInfo.set_last_horse_id(mLastHorseId);

	for (auto it = mHorseItemMap.begin(); it != mHorseItemMap.end(); it++)
	{
		HorseItem& horseItem = it->second;
		auto pHorseDataItem = horseInfo.add_horse_info();
		if (pHorseDataItem)
		{
			horseItem.SaveToPB(*pHorseDataItem);
		}
	}
	return true;
}

bool HorsePart::SaveDB(CharacterDBInfo& characterDB)
{
	auto pHorseData = characterDB.mutable_horsedata();
	if (pHorseData)
	{
		SaveToPB(*pHorseData);
	}
	return true;
}

void HorsePart::SynLogout()
{
	//DismountHorse();
}

bool HorsePart::SynOnLogin(PlayerClientInfo& playerInfo)
{
	CharFacadeProto *facade = playerInfo.mutable_facade();
	if (facade)
	{
		facade->set_cur_horse_id(GetCurHorseId());
	}
	return true;
}

bool HorsePart::Init(Creature *pMaster, uint32_t partType, CharacterDBInfo* pCharacterDB)
{
	::Part::Init(pMaster, partType, pCharacterDB);

	if (pCharacterDB && pCharacterDB->has_horsedata())
	{
		mCurHorseId = pCharacterDB->horsedata().cur_horse_id();
		mLastHorseId = pCharacterDB->horsedata().last_horse_id();
		for (int i = 0; i < pCharacterDB->horsedata().horse_info_size(); i++)
		{
			const ::ProtoBuf::HorseItemInfo& horseInfo = pCharacterDB->horsedata().horse_info(i);
			HorseItem horseItem;
			horseItem.LoadFromPB(horseInfo);

			//
			auto pInfo = g_GetMountMountCfgTable()->GetMountMountCfgInfo(horseItem.GetHorseId());
			if (pInfo == nullptr)
			{
				LogErrFmtPrint("horseId:%d cant find int the mount cfg! will delete the horse!", horseItem.GetHorseId());
				continue;
			}

			//
			int now = (int)g_GetGlobalServerTime()->UnixSec();
			if (horseItem.GetHorseUnLock() && horseItem.GetForever() == false)
			{
				if (horseItem.GetLockTime() + horseItem.GetContinueTime() <= now)
				{
					if (mCurHorseId == horseItem.GetHorseId())
					{
						mCurHorseId = 0;
						mLastHorseId = 0;
					}
					//
					continue;
				}
			}

			mHorseItemMap.emplace(horseItem.GetHorseId(), horseItem);
		}
	}

	if (mCurHorseId > 0)
	{
	 	auto pInfo = g_GetMountMountCfgTable()->GetMountMountCfgInfo(mCurHorseId);
	 	if (pInfo)
	 	{
	 		for(int i = 0; i < (int)pInfo->vecMountMountAttributeCfg.size(); i++)
	 		{
	 			m_pMaster->AddAttr(g_GetAttrMgr()->GetPlayerFightModlePAttr(enFightAttrModule_Horse, pInfo->vecMountMountAttributeCfg[i].type), pInfo->vecMountMountAttributeCfg[i].value, true);
	 		}
	 	}
	}

	SetTimedo(HORSE_PART_TIMER, HORSE_PART_TIMER_INTERNAL);
	return true;
}

bool HorsePart::UnInit()
{
	KillAllTimerdo();
	mHorseItemMap.clear();
	return true;
}

void HorsePart::OnExecute(uint16_t nEventID, uint64_t nSrcID, uint8_t bySrcType, void *pContext, int32_t nLen)
{

}

bool HorsePart::OnMsgHandle(uint32_t cmd, const char* data, uint32_t len)
{
	switch (cmd)
	{
	case CLIENT_TO_LOGIC_GET_HORSE_INFO:
		GetHorseInfoHandle(data, len);
		break;
	case CLIENT_TO_LOGIC_ACTIVE_HORSE:
		ActiveHorseHandle(data, len);
		break;
	case CLIENT_TO_LOGIC_MOUNT_HORSE:
		MountHorseHandle(data, len);
		break;
	case CLIENT_TO_LOGIC_DISMOUNT_HORSE:
		DismountHorseHandle(data, len);
		break;
	default:
		break;
	}
	return true;
}

void HorsePart::OnTimer(uint32_t nTimerId)
{
	switch(nTimerId)
	{
	case HORSE_PART_TIMER:
	{
		HandleHorseTimeOut();
	}
		break;
	default:
		break;
	}
}

void HorsePart::HandleHorseTimeOut()
{
	for(auto it = mHorseItemMap.begin(); it != mHorseItemMap.end();)
	{
		HorseItem& item = it->second;
		if (item.GetForever() == false)
		{
			if (item.GetLockTime() + item.GetContinueTime() < (int32_t)g_GetGlobalServerTime()->UnixSec())
			{
				if (item.GetHorseId() == mCurHorseId)
				{
					DismountHorse();
					mLastHorseId = 0;

//					PlayerDisMountHorseRep respone;
//					respone.set_ret(0);
//					respone.set_cur_horse_id(CurHorseId);
//					respone.set_last_horse_id(LastHorseId);
//
//					m_pMaster->BroadCastData(LOGIC_TO_CLIENT_DISMOUNT_HORSE, &respone, true);

					FacadeBroadcast broadcast;
					broadcast.set_charid(m_pMaster->GetCid());
					::ProtoBuf::CharFacadeProto* pFacade = broadcast.mutable_facade();
					Player* pPlayer = dynamic_cast<Player*>(m_pMaster);
					if (pPlayer)
					{
						pPlayer->GetFacade(pFacade);
					}
					m_pMaster->BroadCastData(LOGIC_TO_CLIENT_FACADE_BROADCAST, (ProtoBufBase*)&broadcast, true);
				}

				NotifyPlayerHorseTimeout timeOut;
				timeOut.set_horse_id(item.GetHorseId());
				
				m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_NOTIFY_HORSE_TIME_OUT, &timeOut);
				
				it = mHorseItemMap.erase(it);
				continue;
			}
		}
		it++;
	}
}

int HorsePart::ActiveHorse(int horseId, int validHour)
{
	int ret = CheckLevel();
	if (ret != 0)
	{
		return ret;
	}

 	auto pInfo = g_GetMountMountCfgTable()->GetMountMountCfgInfo(horseId);
	if (pInfo)
	{
		auto it = mHorseItemMap.find(horseId);
		if (it != mHorseItemMap.end())
		{
			HorseItem& item = it->second;
			if (item.GetForever() == true)	//表示永久
			{
				PlayerActiveHorseRep respone;
				respone.set_ret(RET_HORSE_HORSE_ID_FOR_EVER_EXIST);

				m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);
				return RET_HORSE_HORSE_ID_FOR_EVER_EXIST;
			}
			else if (item.GetForever() == false && validHour < 0) //表示永久
			{
				item.SetHorseId(horseId);
				item.SetContinueTime(0);
				item.SetForever(true);
				item.SetHorseUnLock(true);
			}
			else if (item.GetForever() == false && validHour >= 0)
			{
				item.SetHorseId(horseId);
				item.SetContinueTime(item.GetContinueTime() + validHour * 60 * 60);
				item.SetForever(false);
				item.SetHorseUnLock(true);
			}

			PlayerActiveHorseRep respone;
			respone.set_ret(RET_SUCCESS);
			::ProtoBuf::HorseItemInfo* pInfo = respone.mutable_horse_info();
			if (pInfo)
			{
				item.SaveToPB(*pInfo);
			}
			m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);

			if (validHour < 0)
			{
				HorseActiveEvent horseEvent;
				g_GetEvent()->FireExecute(EVENT_HORSE_ACTIVE, m_pMaster->GetCid(), CREATURE_PLAYER, (HorseActiveEvent*)&horseEvent, sizeof(HorseActiveEvent));
			}

			return RET_SUCCESS;
		}

		HorseItem item;
		if (validHour < 0) //表示永久
		{
			item.SetHorseId(horseId);
			item.SetContinueTime(0);
			item.SetForever(true);
			item.SetHorseUnLock(true);
			item.SetLockTime((int32_t)g_GetGlobalServerTime()->UnixSec());

			HorseActiveEvent horseEvent;
			g_GetEvent()->FireExecute(EVENT_HORSE_ACTIVE, m_pMaster->GetCid(), CREATURE_PLAYER, (HorseActiveEvent*)&horseEvent, sizeof(HorseActiveEvent));
		}
		else
		{
			item.SetHorseId(horseId);
			item.SetContinueTime(validHour * 60 * 60);
			item.SetForever(false);
			item.SetHorseUnLock(true);
			item.SetLockTime((int32_t)g_GetGlobalServerTime()->UnixSec());
		}
		mHorseItemMap.emplace(horseId, item);

		PlayerActiveHorseRep respone;
		respone.set_ret(RET_SUCCESS);
		::ProtoBuf::HorseItemInfo* pInfo = respone.mutable_horse_info();
		if (pInfo)
		{
			item.SaveToPB(*pInfo);
		}
		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);

		return RET_SUCCESS;

	}
	else
	{
		PlayerActiveHorseRep respone;
		respone.set_ret(RET_HORSE_ID_NOT_EXIST);

		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);
		return RET_HORSE_ID_NOT_EXIST;
	}
}

bool HorsePart::MountHorse(int horseId)
{
	if (m_pMaster->HasBuffState(CREATURE_BUFF_DISMOUNT))
	{
		return false;
	}

	auto it = mHorseItemMap.find(horseId);
	if (it == mHorseItemMap.end())
	{
		return false;
	}

	mLastHorseId = horseId;
	mCurHorseId = horseId;

 	auto pInfo = g_GetMountMountCfgTable()->GetMountMountCfgInfo(mCurHorseId);
 	if (pInfo)
 	{
 		for(int i = 0; i < (int)pInfo->vecMountMountAttributeCfg.size(); i++)
 		{

		m_pMaster->AddAttr(g_GetAttrMgr()->GetPlayerFightModlePAttr(enFightAttrModule_Horse, pInfo->vecMountMountAttributeCfg[i].type), pInfo->vecMountMountAttributeCfg[i].value, true);

 		}
 	}

	return true;
}

bool HorsePart::DismountHorse()
{
	if (mCurHorseId <= 0)
	{
		return false;
	}

 	auto pInfo = g_GetMountMountCfgTable()->GetMountMountCfgInfo(mCurHorseId);
 	if (pInfo)
 	{
 		for(int i = 0; i < (int)pInfo->vecMountMountAttributeCfg.size(); i++)
 		{
			m_pMaster->AddAttr(g_GetAttrMgr()->GetPlayerFightModlePAttr(enFightAttrModule_Horse, pInfo->vecMountMountAttributeCfg[i].type), -1 * pInfo->vecMountMountAttributeCfg[i].value, false);
 		}

		//if (!m_pMaster->IsDead())
		{
			m_pMaster->SynAttrToClient();
		}
 	}



	mLastHorseId = mCurHorseId;
	mCurHorseId = 0;

	return true;
}


void HorsePart::SendHourseInfo()
{
	PlayerGetHorseInfoRep respone;
	auto pHorseInfo = respone.mutable_horse_info();
	if (pHorseInfo)
	{
		SaveToPB(*pHorseInfo);
	}
	m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_GET_HORSE_INFO, &respone);
}

void HorsePart::GetHorseInfoHandle(const char* data, uint32_t len)			//
{
	PlayerGetHorseInfoReq request;

	if (!request.ParseFromArray(data, len))
	{
		MMOLOG_FMT_ERROR("[logic] PlayerGetHorseInfoReq parse failed...");
		return;
	}

	PlayerGetHorseInfoRep respone;
	auto pHorseInfo = respone.mutable_horse_info();
	if (pHorseInfo)
	{
		SaveToPB(*pHorseInfo);
	}
	m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_GET_HORSE_INFO, &respone);
}

void HorsePart::ActiveHorseHandle(const char* data, uint32_t len)				//
{
//	PlayerActiveHorseReq request;
//
//	if (!request.ParseFromArray(data, len))
//	{
//		MMOLOG_FMT_ERROR("[logic] PlayerActiveHorseReq parse failed...");
//		return;
//	}
//
//	uint32_t horseId = 0;
//
//	const ItemItemCfgInfo *pItemInfo = g_GetItemItemCfgTable()->GetItemItemCfgInfo(request.item_id());
//	if (pItemInfo == nullptr)
//	{
//		PlayerActiveHorseRep respone;
//		respone.set_ret(1);
//
//		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);
//	}
//
//	const MountMountCfgMap *pMountMap = g_GetMountMountCfgTable()->GetMountMountCfgMap();
//	for(auto it = pMountMap->begin(); it != pMountMap->end(); it++)
//	{
//		const MountMountCfgInfo& mountCfg = it->second;
//		for(auto iter = mountCfg.vec_item.begin(); iter != mountCfg.vec_item.end(); iter++)
//		{
//			if (request.item_id() == (uint32_t)*iter)
//			{
//				horseId = it->first;
//				break;
//			}
//		}
//
//		if (horseId != 0)
//		{
//			break;
//		}
//	}
//
//	if (horseId == 0)
//	{
//		PlayerActiveHorseRep respone;
//		respone.set_ret(1);
//
//		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);
//	}
//
//	PackagePart* pPackagePart = dynamic_cast<PackagePart*>(m_pMaster->GetPart(PART_PACKAGE));
//	if (pPackagePart == nullptr) return;
//
//	int32_t nUnBindNum = 0;
//	int32_t nBindNum = 0;
//	pPackagePart->GetItemNum(request.item_id(), nUnBindNum, nBindNum);
//	if (nBindNum + nUnBindNum <= 0)
//	{
//		PlayerActiveHorseRep respone;
//		respone.set_ret(1);
//
//		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);
//	}
//
//	bool ret = ActiveHorse(horseId);
//
//	if (ret)
//	{
//		pPackagePart->AddItem(request.item_id(), -1);
//		PlayerActiveHorseRep respone;
//		respone.set_ret(0);
//		auto it = HorseItemMap.find(horseId);
//		if (it != HorseItemMap.end())
//		{
//			HorseItem& item = it->second;
//			::ProtoBuf::HorseItemInfo* pInfo = respone.mutable_horse_info();
//			if (pInfo)
//			{
//				item.SaveToPB(*pInfo);
//			}
//		}
//
//		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);
//	}
//	else
//	{
//		PlayerActiveHorseRep respone;
//		respone.set_ret(2);
//
//		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_ACTIVE_HORSE, &respone);
//	}

}

void HorsePart::MountHorseHandle(const char* data, uint32_t len)				//
{
	PlayerMountHorseReq request;

	if (!request.ParseFromArray(data, len))
	{
		MMOLOG_FMT_ERROR("[logic] PlayerMountHorseReq parse failed...");
		return;
	}

	if (mCurHorseId > 0)
	{
		if ((uint32_t)mCurHorseId == request.horse_id())
		{
			MMOLOG_FMT_DEBUG("HorsePart::MountHorseHandle on horse  same horse id  = %d",request.horse_id());
			return;
		}

		DismountHorse();

		//PlayerDisMountHorseRep respone;
		//respone.set_ret(0);
		//respone.set_cur_horse_id(mCurHorseId);
		//respone.set_last_horse_id(mLastHorseId);

		//m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_DISMOUNT_HORSE, &respone);

		//FacadeBroadcast broadcast;
		//broadcast.set_charid(m_pMaster->GetCid());
		//::ProtoBuf::CharFacadeProto* pFacade = broadcast.mutable_facade();
		//Player* pPlayer = dynamic_cast<Player*>(m_pMaster);
		//if (pPlayer)
		//{
		//	pPlayer->GetFacade(pFacade);
		//}
		//m_pMaster->BroadCastData(EMODULE_ID_PACKAGE, LOGIC_TO_CLIENT_FACADE_BROADCAST, (ProtoBufBase*)&broadcast, true);

	}

	bool ret = MountHorse(request.horse_id());
	if (ret)
	{
		PlayerMountHorseRep respone;
		respone.set_ret(0);
		respone.set_cur_horse_id(mCurHorseId);
		respone.set_last_horse_id(mLastHorseId);

		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_MOUNT_HORSE, &respone);

		FacadeBroadcast broadcast;
		broadcast.set_charid(m_pMaster->GetCid());
		::ProtoBuf::CharFacadeProto* pFacade = broadcast.mutable_facade();
		Player* pPlayer = dynamic_cast<Player*>(m_pMaster);
		if (pPlayer)
		{
			pPlayer->GetFacade(pFacade);
		}
		m_pMaster->BroadCastData(EMODULE_ID_PACKAGE, LOGIC_TO_CLIENT_FACADE_BROADCAST, (ProtoBufBase*)&broadcast, true);

		LogicToCenterCharFacadeSync sync;
		sync.set_charid(m_pMaster->GetCid());
		sync.mutable_facade()->CopyFrom(*pFacade);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_SERV_SYS, LOGIC_TO_CENTER_SYNC_FACADE_DATA, &sync);
	}
	else
	{
		PlayerMountHorseRep respone;
		respone.set_ret(1);

		m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_MOUNT_HORSE, &respone);
	}
}

void HorsePart::DismountHorseHandle(const char* data, uint32_t len)			//
{
	PlayerDisMountHorseReq request;

	if (!request.ParseFromArray(data, len))
	{
		MMOLOG_FMT_ERROR("[logic] PlayerDisMountHorseReq parse failed...");
		return;
	}

	DismountHorse();

	PlayerDisMountHorseRep respone;
	respone.set_ret(0);
	respone.set_cur_horse_id(mCurHorseId);
	respone.set_last_horse_id(mLastHorseId);

	m_pMaster->SendDataToClient(LOGIC_TO_CLIENT_DISMOUNT_HORSE, &respone);

	FacadeBroadcast broadcast;
	broadcast.set_charid(m_pMaster->GetCid());
	::ProtoBuf::CharFacadeProto* pFacade = broadcast.mutable_facade();
	Player* pPlayer = dynamic_cast<Player*>(m_pMaster);
	if (pPlayer)
	{
		pPlayer->GetFacade(pFacade);
	}

	m_pMaster->BroadCastData(EMODULE_ID_PACKAGE, LOGIC_TO_CLIENT_FACADE_BROADCAST, (ProtoBufBase*)&broadcast, true);

	LogicToCenterCharFacadeSync sync;
	sync.set_charid(m_pMaster->GetCid());
	sync.mutable_facade()->CopyFrom(*pFacade);
	g_GetLogicService()->SendDataToCenter(EMODULE_ID_SERV_SYS, LOGIC_TO_CENTER_SYNC_FACADE_DATA, &sync);
}
